*** Nonpartisan Primaries, Open Primaries, and Voter Turnout
*** Nathan K. Micatka, Caroline J. Tolbert, & Robert G. Boatright
*** Journal of Political Institutions and Political Economy
*** Replication Code
*** Updated: June 13, 2024
********************************************************************

/* Below is first the code for creating Figure 1 and Figure 2. Following this is the remaining code for replicating the Tables and Figures 3-5. */

use BPC_USEP_Map.dta

*Convert shapefile to DTA files
shp2dta using cb_2018_us_state_500k, data(states18) coor(states18-coord) replace

*Must destring GEOID
use states18
destring GEOID, gen(fips)
save states18, replace
clear all

*Open DTA and merge with state data
use BPC_USEP_Map.dta, clear
gen fips=state_identification
drop _merge
merge 1:1 fips using states18
drop if _merge != 3

gen bpcprimary_vote2018_percent=(bpc_turnout_2018*100)
gen bpcprimary_vote2022_percent=(bpc_turnout_2022*100)

gen vep2018_percent=(vep_turnout_rate2018*100)
gen vep2020_percent=(vep_turnout_rate2020*100)
gen vep2022_percent=(vep_turnout_rate2022*100)

gen vap2018_percent=(vap_turnout_rate2018*100)
gen vap2020_percent=(vap_turnout_rate2020*100)
gen vap2022_percent=(vap_turnout_rate2022*100)

*Make prettier maps
save maps-turnout, replace
clear all
use states18-coord
geo2xy _Y _X, replace
save states18-geo2xy, replace

clear all
use maps-turnout

*Bimap
drop if STATEFP == "02"
drop if STATEFP == "15"
bimap vap2022_percent bpcprimary_vote2022_percent using states18-geo2xy, cut(pctile) palette(greenblue) textx("Primary Vote 2022 (BPC)") texty("General Vote 2022 (USEP)") 

bimap vap2018_percent bpcprimary_vote2018_percent using states18-geo2xy, cut(pctile) palette(greenblue) textx("Primary Vote 2018 (BPC)") texty("General Vote 2018 (USEP)") 

/* Here starts the code for descriptives, modeling, tables, and margins/predicted probabilities. */

*** loading in data
use MicatkaTolbertBoatright_JPIPE_Data.dta, clear

*** DESCRIPTIVES
** Looking at Turnout by State Primary Law Type
* Overall
tabstat vote_2022p, statistics(mean) by(primary_type)
tabstat vote_2018p, statistics(mean) by(primary_type)

* Democrats
tabstat vote_2022p if pid3_catalist==3, statistics(mean) by(primary_type)
tabstat vote_2018p if pid3_catalist==3, statistics(mean) by(primary_type)

* Republicans
tabstat vote_2022p if pid3_catalist==1, statistics(mean) by(primary_type)
tabstat vote_2018p if pid3_catalist==1, statistics(mean) by(primary_type)

* Independents
tabstat vote_2022p if pid3_catalist==2, statistics(mean) by(primary_type)
tabstat vote_2018p if pid3_catalist==2, statistics(mean) by(primary_type)


*** MODELING
** Table 1
* Overall/Base Model
logit vote_2022p vote_2018p age_bounded_100 age_bounded_100_sq female income educ_prob_college married asian_fix black_nh_fix hisp_fix race_other_nh_fix ideology_continuous rsfrac_2022 rgfrac_2022 dsfrac_2022  dgfrac_2022 i.open_unaff_primary i.open_primary i.non_partisan_primary, cluster(state_identification)
estimates store overall_pto_all

* Republicans
logit vote_2022p vote_2018p age_bounded_100 age_bounded_100_sq female income educ_prob_college married asian_fix black_nh_fix hisp_fix race_other_nh_fix ideology_continuous rsfrac_2022  rgfrac_2022 i.open_unaff_primary i.open_primary i.non_partisan_primary if pid3==1, cluster(state_identification)
estimates store repub_pto_all

* Independents
logit vote_2022p vote_2018p age_bounded_100 age_bounded_100_sq female income educ_prob_college married asian_fix black_nh_fix hisp_fix race_other_nh_fix ideology_continuous rsfrac_2022 rgfrac_2022 dsfrac_2022  dgfrac_2022 i.open_unaff_primary i.open_primary i.non_partisan_primary if pid3==2, cluster(state_identification)
estimates store indpt_pto_all

* Democrats
logit vote_2022p vote_2018p age_bounded_100 age_bounded_100_sq female income educ_prob_college married asian_fix black_nh_fix hisp_fix race_other_nh_fix ideology_continuous  dsfrac_2022  dgfrac_2022 i.open_unaff_primary i.open_primary i.non_partisan_primary if pid3==3, cluster(state_identification)
estimates store dem_pto_all

** Table 3
** Interaction Model 1 - Indept * non-partisan primary
logit vote_2022p vote_2018p age_bounded_100 age_bounded_100_sq female income educ_prob_college married asian_fix black_nh_fix hisp_fix race_other_nh_fix ideology_continuous rsfrac_2022 rgfrac_2022 dsfrac_2022 dgfrac_2022 i.open_unaff_primary i.open_primary i.non_partisan_primary##i.indpt, cluster(state_identification)
estimates store inter_model1

** Interaction Model 2 - Indept * open_primary
logit vote_2022p vote_2018p age_bounded_100 age_bounded_100_sq female income educ_prob_college married asian_fix black_nh_fix hisp_fix race_other_nh_fix ideology_continuous rsfrac_2022 rgfrac_2022 dsfrac_2022 dgfrac_2022 i.open_unaff_primary i.non_partisan_primary i.open_primary##i.indpt, cluster(state_identification)
estimates store inter_model2

** Interaction Model 3 - Indept * open_unaff_primary
logit vote_2022p vote_2018p age_bounded_100 age_bounded_100_sq female income educ_prob_college married asian_fix black_nh_fix hisp_fix race_other_nh_fix ideology_continuous rsfrac_2022 rgfrac_2022 dsfrac_2022 dgfrac_2022 i.open_primary i.non_partisan_primary i.open_unaff_primary##i.indpt, cluster(state_identification)
estimates store inter_model3

*** CREATING TABLES
** Table 1
esttab overall_pto_all  repub_pto_all  indpt_pto_all dem_pto_all using Overall_PTO_Models_2023File.csv, replace se(3) label  ///
		b(%9.2f) star(* .1 ** .05 *** .01) nolz nobase nogaps s(N ll r2_p bic) ///
		varlabels(age_bounded_100 "Age" age_bounded_100_sq "Age Squared" female "Female" asian_fix "Asian" black_nh_fix "Black" hisp_fix "Latino" ///
		race_other_nh_fix "Race Other" married "Married" educ_prob_college "Pr(Bachelor's degree)" income "Income" ideology_continuous ///
		"Catalist Ideology" _cons "Constant" 1.open_unaff_primary "Open-Unaffl. Voters Primary State" 1.open_primary "Open Primary State" ///
		1.non_partisan_primary "Non-partisan Primary State" ///
		rsfrac_2022 "Rep. Senate Fract. 2022" dsfrac_2022 "Dem. Senate Fract. 2022" ///
		rgfrac_2022 "Rep. Governor Fract. 2022" dgfrac_2022 "Dem. Governor Fract. 2022" vote_2018p "Vote in 2018 Primary") ///
		mtitles("Overall" "Republicans" ///
		"Independents" "Democrats" ) ///
		order(vote_2018p age_bounded_100  age_bounded_100_sq female asian_fix black_nh_fix hisp_fix race_other_nh_fix married educ_prob_college income ///
		ideology_continuous 1.open_unaff_primary 1.open_primary 1.non_partisan_primary dsfrac_2022 dgfrac_2022 rsfrac_2022 rgfrac_2022)
		
** Table 3 - interactions
esttab inter_model1  inter_model2 inter_model3 using Overall_PTO_ModelsInteractions.csv, replace se(3) label  ///
		b(%9.2f) star(* .1 ** .05 *** .01) nolz nobase nogaps s(N ll r2_p bic) ///
		varlabels(age_bounded_100 "Age" age_bounded_100_sq "Age Squared" female "Female" asian_fix "Asian" black_nh_fix "Black" hisp_fix "Latino" ///
		race_other_nh_fix "Race Other" married "Married" educ_prob_college "Pr(Bachelor's degree)" income "Income" ideology_continuous ///
		"Catalist Ideology" _cons "Constant" 1.open_unaff_primary "Open-Unaffl. Voters Primary State" 1.open_primary "Open Primary State" ///
		1.non_partisan_primary "Non-partisan Primary State" rsfrac_2022 "Rep. Senate Fract. 2022" dsfrac_2022 "Dem. Senate Fract. 2022" ///
		rgfrac_2022 "Rep. Governor Fract. 2022" dgfrac_2022 "Dem. Governor Fract. 2022" 1.indpt "Independent" ///
		1.non_partisan_primary#1.indpt "Non-partisan primary * Independent" ///
		1.open_unaff_primary#1.indpt "Open Unaffl. Primary * Independent" ///
		1.open_primary#1.indpt "Open Primary * Independent") ///
		mtitles("Interacting Non-Partisan Primary and Independent" "Interacting Open Unaffl. Primary and Independent" ///
		"Interacting Open Primary and Indpendent") ///
		order(vote_2018p 1.indpt 1.non_partisan_primary 1.non_partisan_primary#1.indpt ///
		1.open_primary 1.open_primary#1.indpt ///
		1.open_unaff_primary 1.open_unaff_primary#1.indpt ///
		ideology_continuous age_bounded_100  age_bounded_100_sq ///
		female asian_fix black_nh_fix hisp_fix race_other_nh_fix married educ_prob_college income ///
		dsfrac_2022 dgfrac_2022 rsfrac_2022 rgfrac_2022)


*** MARGINAL EFFECTS AND PREDICTED PROBABILITIES
** Figure 3
estimates restore dem_pto_all
margins, at(dsfrac_2022=(-.288(.22).592)) atmeans
marginsplot, ///
	xlabel( -.288 "-2 SD"  -.068 "-1 SD" .152 "Mean" .372 "+1 SD" .592 "+2 SD", labsize(small)) ///
	xtitle("Democratic Senate Fract. 2022") ///
	ytitle("Pr(Voting in 2022 Primary)") ///
	title(" ") aspectratio(.55) ///
	name(pto_dems_frac, replace)

** Figure 4
estimates restore repub_pto_all
margins, at(rgfrac_2022=(-.298(.31).942)) atmeans
marginsplot, ///
	xlabel( -.298 "-2 SD"  .012 "-1 SD" .322 "Mean" .632 "+1 SD" .942 "+2 SD", labsize(small)) ///
	xtitle("Republican Governor Fract. 2022") ///
	ytitle("Pr(Voting in 2022 Primary)") ///
	title(" ") aspectratio(.55) ///
	name(pto_repg_frac, replace)

** Figure 5
estimates restore inter_model1
margins non_partisan_primary, at(indpt=(0(1)1) open_primary==0 open_unaff_primary==0) atmeans
marginsplot, ///
	xlabel( 0 "Non-independents" 1 "Independents", labsize(small)) xtitle(" ") ///
	ytitle("Pr(Voting in 2022 Primary)") ///
	title(" ") aspectratio(.55) ///
	legend(on) legend(order(1 "Partisan Primary State" 2 "Non-partisan Primary State")) name(inter_model1_lagmean_graph, replace)

** Table 2
estimates restore overall_pto_all
margins, dydx(non_partisan_primary) at(open_unaff_primary==0 open_primary==0) atmeans /* nonpartisan primary */

estimates restore repub_pto_all
margins, dydx(non_partisan_primary) at(open_unaff_primary==0 open_primary==0) atmeans /* nonpartisan primary */
margins, dydx(rgfrac_2022) atmeans /* Rep. governor competition  */

estimates restore indpt_pto_all
margins, dydx(non_partisan_primary) at(open_unaff_primary==0 open_primary==0) atmeans /* nonpartisan primary */
margins, dydx(open_primary) at(open_unaff_primary==0 non_partisan_primary==0) atmeans /* open primary  */

estimates restore dem_pto_all
margins, dydx(non_partisan_primary) at(open_unaff_primary==0 open_primary==0) atmeans /* nonpartisan primary */
margins, dydx(open_primary) at(open_unaff_primary==0 non_partisan_primary==0) atmeans /* open primary  */
margins, dydx(dsfrac_2022) atmeans /* Dem. senate competition  */
